﻿#include "TranscodingWindow.h"
#include <QFileDialog>
#include <QSize>
#include <QMessageBox>
#include <Qt>
#include <QDebug>

extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
}

TranscodingWindow::TranscodingWindow(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	this->setWindowTitle("综合案例之视频转码");
	setAttribute(Qt::WA_DeleteOnClose, true);  // 关闭时自动销毁窗口
}

void TranscodingWindow::OnSrcFileSelected()
{
	QString filter = "所有文件(*.*)"; //文件过滤器
	QString filePath = QFileDialog::getOpenFileName(this, "选择输入文件", "", filter);
	this->srcFilePath = filePath;
	this->ui.lineEdit_src_path->setText(this->srcFilePath);
}

void TranscodingWindow::OnDstOutputFileSelected()
{
	QString filter = "所有文件(*.*)"; //文件过滤器
	QString filePath = QFileDialog::getSaveFileName(this, "选择输出文件", "", filter);
	this->dstFilePath = filePath;
	this->ui.lineEdit_target_path->setText(this->dstFilePath);
}

void TranscodingWindow::OnCodecFormatChanged(int pos)
{
	switch (pos)
	{
	case 0://保持不变
		codecId = AV_CODEC_ID_H264;
		break;
	case 1://H264
		codecId = AV_CODEC_ID_H264;
		break;
	case 2://H265
		//codecId = AV_CODEC_ID_HEVC;
		codecId = AV_CODEC_ID_H265;
		break;
	}
}

void TranscodingWindow::OnStartTransfer()
{
	if (this->dstFilePath.isEmpty() || this->srcFilePath.isEmpty()) {
		QMessageBox::information(this, "温馨提示", "参数不对请检查参数");
		return;
	}
	targetVideoWidth = this->ui.lineEdit_target_width->text().toInt();
	targetVideoHeight = this->ui.lineEdit_target_height->text().toInt();
	begin_seconds = this->ui.lineEdit_start_time->text().toDouble();//开始截取时间
	end_seconds = this->ui.lineEdit_end_time->text().toDouble();//结束截取时间
	isRunning = true;
	//封装/解封装器
	demuxer = new YDemuxer();
	muxer = new YMuxer();
	//编码/解码器
	decoder = new YDecoder();
	encoder = new YEncoder();

	renderThread = std::make_unique<std::thread>(&TranscodingWindow::OnTransfer, this);
}

void TranscodingWindow::OnTransfer()
{
	///////////封装及解封装////////////////////
	auto ic = demuxer->Open(this->srcFilePath.toStdString().c_str());
	demuxer->setContext(ic);

	auto oc = muxer->Open(this->dstFilePath.toStdString().c_str());
	muxer->setContext(oc);
	auto o_vs = oc->streams[muxer->GetVideoIndex()];//视频流信息
	auto o_as = oc->streams[muxer->GetAudioIndex()];//音频流信息


	if (demuxer->GetVideoIndex() >= 0)//输入文件中有视频数据
	{
		o_vs->time_base.den = demuxer->GetVideoTimeBase().den;
		o_vs->time_base.num = demuxer->GetVideoTimeBase().num;
		//将输入的视频参数复制到输出中
		demuxer->CopyInCodecParametersToOut(demuxer->GetVideoIndex(), o_vs->codecpar);
	}

	if (demuxer->GetAudioIndex() >= 0)//输入文件中有音频数据
	{
		o_as->time_base.den = demuxer->GetAudioTimeBase().den;
		o_as->time_base.num = demuxer->GetAudioTimeBase().num;
		//将输入的音频参数复制到输出中
		demuxer->CopyInCodecParametersToOut(demuxer->GetAudioIndex(), o_as->codecpar);
	}



	if (begin_seconds > 0 && end_seconds > 0)
	{
		//计算开始的pts和结束的pts
	   //pts = seconds/(num/den)=seconds*(den/num)
		if (demuxer->GetVideoIndex() >= 0 && demuxer->GetVideoTimeBase().num > 0)
		{
			double t = (double)demuxer->GetVideoTimeBase().den / (double)demuxer->GetVideoTimeBase().num;//den分母/num分子
			begin_pts = begin_seconds * t;
			end_pts = end_seconds * t;
			demuxer->Seek(begin_pts, demuxer->GetVideoIndex());
			int beginSeconds = begin_pts/ t;
			int endSeconds = end_pts / t;
			qDebug() << "开始时间：" << beginSeconds;
			qDebug() << "结束时间：" << endSeconds;
		}

		if (demuxer->GetAudioIndex() >= 0 && demuxer->GetAudioTimeBase().num > 0)
		{
			begin_audio_pts = begin_seconds * ((double)demuxer->GetAudioTimeBase().den / (double)demuxer->GetAudioTimeBase().num);
		}

	}
	///////////解码及编码////////////////////
	auto deContext = decoder->Create(demuxer->GetVideoCodecId(), false);
	decoder->setContext(deContext);
	//设置解码器参数
	demuxer->CopyParaParameters(demuxer->GetVideoIndex(), deContext);
	decoder->Open();
	auto frame = decoder->CreateFrame();
	//auto frame = av_frame_alloc();

	if (codecId == 0)
	{
		codecId = demuxer->GetVideoCodecId();
	}
	auto enContext = encoder->Create(codecId, true);
	encoder->setContext(enContext);
	enContext->pix_fmt = AV_PIX_FMT_YUV420P;
	enContext->width = demuxer->GetVideoWidth();
	enContext->height = demuxer->GetVideoHeight();
	/*enContext->framerate = {25,1};
	enContext->max_b_frames = 0;
	enContext->gop_size = 30;
	enContext->codec_tag = 0;*/

	if (targetVideoWidth > 0 && targetVideoHeight > 0)
	{
		enContext->width = targetVideoWidth;
		enContext->height = targetVideoHeight;
	}
	encoder->Open();
	////////////////////////
	////复制编码器格式到上下文
	if (demuxer->GetVideoIndex() >= 0)//输入文件中有视频数据
	{
		o_vs->time_base.num = demuxer->GetVideoTimeBase().num;
		o_vs->time_base.den = demuxer->GetVideoTimeBase().den;
		// 复制编码器格式，确保编码参数能够正确的传递给输出格式上下文（AVFormatContext *oc）
		avcodec_parameters_from_context(o_vs->codecpar, enContext);//o_vs是新创建的流，需要把编码格式告诉他，然后才行
	}

	if (demuxer->GetAudioIndex() >= 0)//输入文件中有音频数据
	{
		o_as->time_base.num = demuxer->GetAudioTimeBase().num;
		o_as->time_base.den = demuxer->GetAudioTimeBase().den;
		//复制音频参数
		demuxer->CopyParaParameters(demuxer->GetAudioIndex(), enContext);
		//avcodec_parameters_from_context(o_as->codecpar, enContext);
	}

	////视频格式转换////////////
	if (targetVideoWidth > 0 && targetVideoHeight > 0)
	{
		videoReScaler = new VideoReScaler();
		//初始化输入视频的宽高和输出视频的宽高
		videoReScaler->Init(demuxer->GetVideoWidth(), demuxer->GetVideoHeight(), AV_PIX_FMT_YUV420P, targetVideoWidth, targetVideoHeight, AV_PIX_FMT_YUV420P);
		////视频格式转换end////
	}



	//写入头部
	muxer->WriteHead();

	int audio_count = 0;//音频真总数
	int video_count = 0;//视频帧总数
	double total_sec = 0;//总时长

	AVPacket pkt;
	while (isRunning)
	{
		if (!demuxer->Read(&pkt))break;

		// 视频 时间大于结束时间
		if (begin_pts > 0
			&& pkt.stream_index == demuxer->GetVideoIndex()
			&& pkt.pts > end_pts)
		{
			double t = (double)demuxer->GetVideoTimeBase().den / (double)demuxer->GetVideoTimeBase().num;//den分母/num分子
			int endSeconds = pkt.pts / t;
			qDebug() << "结束时间：" << endSeconds;
			av_packet_unref(&pkt);
			break;
		}
		if (pkt.stream_index == demuxer->GetVideoIndex())
		{
			muxer->RescaleTime(&pkt, begin_pts, demuxer->GetVideoTimeBase());

			if (decoder->Send(&pkt))
			{
				while (decoder->Receive(frame))
				{
					if (targetVideoWidth > 0 && targetVideoHeight > 0)
					{
						//修改图像尺寸
						videoReScaler->StartScale(frame);
					}
					//对视频进行重新编码
					auto rePkt = encoder->Encode(frame);
					if (rePkt)
					{
						rePkt->stream_index = muxer->GetVideoIndex();
						muxer->Write(rePkt);
					}
				}
			}


			video_count++;
			if (demuxer->GetVideoTimeBase().den > 0)
				total_sec += pkt.duration * ((double)demuxer->GetVideoTimeBase().num / (double)demuxer->GetVideoTimeBase().den);
		}
		else if (pkt.stream_index == demuxer->GetAudioIndex())
		{
			muxer->RescaleTime(&pkt, begin_audio_pts, demuxer->GetAudioTimeBase());
			audio_count++;
			//写入视频帧
			if (!muxer->Write(&pkt))break;
		}
		else {
			av_packet_unref(&pkt);
		}
	}

	auto pkts = encoder->End();
	for (auto pkt : pkts)
	{
		pkt->stream_index = muxer->GetVideoIndex();
		muxer->Write(pkt);
		av_packet_free(&pkt);
	}

	//写入视频尾部
	muxer->WriteEnd();




	if (demuxer) {
		demuxer->Close();
		delete demuxer;
	}

	if (muxer)
	{
		muxer->Close();
		delete muxer;
	}

	if (videoReScaler)
	{
		videoReScaler->Release();
		delete videoReScaler;
		videoReScaler = nullptr;
	}

	if (encoder)
	{
		encoder->Release();
		delete encoder;
		encoder = nullptr;
	}
	if (decoder)
	{
		delete decoder;
		decoder = nullptr;
	}

	qDebug() << "视频帧:" << video_count;
	qDebug() << "音频帧:" << audio_count;
	qDebug() << "总时长:" << total_sec;

	qDebug() << "解封装结束";


}

void TranscodingWindow::closeEvent(QCloseEvent* event) {
	event->accept();  // 接受关闭事件（允许关闭）
	if (isRunning && renderThread->joinable()) {
		renderThread->join();
		renderThread = nullptr;
	}
	qDebug() << "窗口已关闭";
}
TranscodingWindow::~TranscodingWindow()
{
}
